package cn.funnymap.lgis.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.StandardCharsets;

/**
 * @author jiaoxn
 */
@ConditionalOnClass({RedisTemplate.class, ObjectMapper.class, PolymorphicTypeValidator.class})
public class CustomGenericJackson2JsonRedisSerializer extends GenericJackson2JsonRedisSerializer {
    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper();
        // 设置 ObjectMapper 的可见性，将所有属性设置为可见性，包括私有属性
        OBJECT_MAPPER.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 配置 ObjectMapper，在遇到未知属性时也不抛出异常
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
        // 配置 ObjectMapper，添加全类名
        OBJECT_MAPPER.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY
        );
    }

    public CustomGenericJackson2JsonRedisSerializer() {
        super(OBJECT_MAPPER);
    }

    @Override
    public byte[] serialize(Object source) throws SerializationException {
        if (source instanceof String) {
            return ((String) source).getBytes(StandardCharsets.UTF_8);
        } else {
            try {
                return OBJECT_MAPPER.writeValueAsBytes(source);
            } catch (Exception e) {
                throw new SerializationException("Could not serialize: " + e.getMessage(), e);
            }
        }
    }
    @Override
    public Object deserialize(byte[] source) throws SerializationException {
        if (source == null || source.length == 0) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(source, Object.class);
        } catch (Exception e) {
            throw new SerializationException("Could not deserialize: " + e.getMessage(), e);
        }
    }
}
